let W = null

// 6.封装一个Watch类
class Watcher {
    constructor(obj, key) {
        this.obj = obj
        this.key = key

        // 当要获取值的时候，把当前的watcher保存在全局变量上
        W = this
        this.get()
        // 在get中用完w，就把W设置回去
        W = null
    }

    // 当组件内new Watcher 的时候就是想得到一个值，所以封装一个get方法拿值
    get() {
        // 一旦这样拿值,就会直接进入当前key的响应式的getter函数中
        return this.obj[this.key]
    }

    // 在watcher内部封装一个update方法,当通知我更新的时候,直接调用当前的update方法
    update() {
        console.log('重新请求数据：' + this.get() + '重新渲染视图');
    }
}

// 5.定义一个Dep类，用来收集依赖 通知更新
class Dep {
    constructor() {
        // 每次实例化Dep的时候就会创建一个空的数组，用来保存所有的watcher
        this.subs = []
    }

    depend(watcher) {
        this.subs.push(watcher)
        console.log('每次访问我的数据的时候,我就把watcher收集到dep.subs这个数组中');
    }

    notify() {
        console.log('通知所有的watcher 重新加载新的数据');
        this.subs.forEach(watcher => {
            watcher.update()
        })
    }
}

// 4.封装函数，主要是为了对单个数据做数据劫持
function defineReactive(_data, key, value) {
    // 把value值在交给observe方法，进行深层次的数据响应式
    observe(value)

    // 每次对一个值进行响应式的时候，实例化一个Dep类
    const dep = new Dep()

    Object.defineProperty(_data, key, {
        get() {
            console.log('正在获取' + key + '的值', '收集所有依赖项watcher');

            //当这个数据被请求的时候,把观察者watcher收集起来到dep.subs中
            //我们可能不在模板解析的时候(也就是不是Watcher来要数据),我们需要做判断处理
            if (W) {
                dep.depend(W)
            }

            return value
        },
        set(newVal) {
            if (newVal === value) return

            console.log('正在设置' + key + '的值', '通知所有的watcher进行更新');
            value = newVal
            // 当我的响应数据被修改的时候，通知所有的dep.subs里的watcher进行更新
            dep.notify()
        }
    })
}

// 3.封装一个Observer类，主要用来处理发布订阅模式的核心操作
// 响应式操作：收集依赖，通知更新
class Observer {
    constructor(_data) {
        this._data = _data

        // 判断当前的_data是对象还是数组
        if (Array.isArray(_data)) {
            this.observeArray(_data)
        } else {
            this.walk(_data)
        }
    }

    // 在Observer的原型对象上封装一个对数组操作的方法
    observeArray(_data) {
        _data.forEach(item => {
            observe(item)
        })
    }

    // 在Observer的原型对象上封装一个对对象操作的方法
    walk(_data) {
        for (let key of Object.keys(_data)) {
            // 把每一个数据的响应式核心代码交给defineReactive函数处理
            defineReactive(_data, key, _data[key])
        }
    }
}


// 2. 封装一个observe函数，接收_data，遍历_data的值，一个个的进行数据劫持
function observe(_data) {
    if (typeof _data !== 'object' || _data === null) return

    new Observer(_data)
}


// 1.封装一个Vue的构造函数
function Vue(options) {
    this._data = options.data

    // 数据代理，把_data中的属性取出来，一个个放在vue实例上
    for (let key of Object.keys(this._data)) {
        Object.defineProperty(this, key, {
            get() {
                return this._data[key]
            },
            set(newVal) {
                this._data[key] = newVal
            }
        })
    }

    // 拿到_data的数据开始进行响应式操作，
    observe(this._data)
}

// 实例化
const vm = new Vue({
    data: {
        count: 1,
        course: {
            type: 'easy',
            name: 'html'
        }
    }
})


console.log(vm);

function huoqu() {
    // console.log(vm.count);
    // 模拟模板解析，每个组件都会实例化一个watcher 然后开始观察数据
    new Watcher(vm, 'count')
}

function shezhi() {
    // vm.count++;
    vm.count = 3
}

huoqu();
shezhi();